package com.fingard.dsp.bank.directbank.crbc01;

import org.apache.commons.lang3.StringUtils;

import com.fingard.client.DspClient;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.NodeSalaryItem;
import com.fingard.dsp.bank.directConfig.SalaryConfig;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.bankInterface.IBatPayRec;
import com.fingard.dsp.bank.directbank.crbc01.util.CrbankDES;
import com.fingard.dsp.bank.directbank.crbc01.util.CrbankFileHash;
import com.fingard.dsp.bank.directbank.crbc01.util.CrbankFileZip;
import com.fingard.dsp.bank.directbank.crbc01.util.CrbankRsa;
import com.fingard.dsp.bank.helpers.FileType;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.detail.RetAtsBatPayRecDetail;
import com.fingard.dsp.bank.reqrespobj.single.detail.ReqPayRecDetail;
import com.fingard.dsp.salaryset.SalaryDecrypt;
import com.fingard.net.ConnState;
import com.fingard.net.TcpReceiver;
import com.fingard.text.StringHelper;
import com.fingard.util.DateHelper;
import com.fingard.util.RSAEncryptHelper;
import com.fingard.util.secret.salary.DESUtil;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

import javax.crypto.Cipher;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.util.*;

public class CRBC01BatPayRec extends CRBC01Base implements IBatPayRec {

    /**
     * 工资密钥查询
     * @return
     * @throws Exception
     */
    private String qrySecretKey() throws Exception {
        String secretKey = null;
        //region 一：封装请求报文
        XmlTextWriter xmlWriter = new XmlTextWriter();
        CRBC01Header bankHeader = new CRBC01Header();
        bankHeader.tranCode = "400008";
        bankHeader.tranTime = new Date();
        writeCommonHeader(xmlWriter, bankHeader);
        xmlWriter.writeStartElement("BODY");
        xmlWriter.writeEndElement();//body
        xmlWriter.writeEndElement();//CRBANK
        xmlWriter.writeEndDocument();
        //endregion

        //region 二：发送请求报文
        String[] retStrArr = sendToBank(xmlWriter.toXmlString());
        //endregion

        //region 三：解析响应报文
        if (retStrArr[0].length() == 0) {
            StringBuilder tmpSbMsg = new StringBuilder();
            XmlTextReader tmpBkReader = loadBankRespXmlReader(retStrArr[1], tmpSbMsg);
            if (tmpBkReader != null) {
                String tmpRetCode = tmpBkReader.getFirstText("/CRBANK/HEAD/RET_CODE");
                String tmpRetInfo = tmpBkReader.getFirstText("/CRBANK/HEAD/RET_MSG");
                if ("000000".equals(tmpRetCode)) {
                    secretKey = tmpBkReader.getFirstText("/CRBANK/BODY/KEY");
                } else {
                    throw new RuntimeException(tmpRetInfo);
                }
            }
        }
        //endregion
        return secretKey;
    }

    /**
     * 将发薪明细内容写入对应文件中
     * @param p_req1988
     * @param sourceFileFullPath
     * @throws Exception
     */
    private void writeBatPayDetailFile(ReqBatPayRec p_req1988, String sourceFileFullPath) throws Exception {
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new FileWriter(sourceFileFullPath));
            while (p_req1988.readRecord()) {
                ReqPayRecDetail detail = p_req1988.readedDetail;
                bw.write(detail.askNumber);
                bw.write("|");
                if ("1".equals(detail.sameBnk)) {
                    bw.write("0");
                } else if ("0".equals(detail.sameBnk)) {
                    bw.write("1");
                }
                bw.write("|");
                bw.write(detail.cnapsCode);
                bw.write("|");
                bw.write(detail.recBankLocation);
                bw.write("|");
                bw.write(detail.recAct);
                bw.write("|");
                bw.write(detail.recName);
                bw.write("|");
                bw.write(detail.payAmount);
                bw.write("|");
                bw.write(detail.useType);
                bw.newLine();
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (bw != null) {
                bw.flush();
                bw.close();
            }
        }
    }
    //组装文件内容
    private String getBatPayDetail(ReqBatPayRec p_req1988) throws Exception {
        StringBuilder stringBuilder = new StringBuilder();
        while (p_req1988.readRecord()){
            ReqPayRecDetail detail = p_req1988.readedDetail;
            stringBuilder.append(detail.askNumber);
            stringBuilder.append("|");
            if("1".equals(detail.sameBnk)){
                stringBuilder.append("0");
            }else if("0".equals(detail.sameBnk)){
                stringBuilder.append("1");
            }
            stringBuilder.append("|");
            stringBuilder.append(detail.cnapsCode);
            stringBuilder.append("|");
            stringBuilder.append(detail.recBankLocation);
            stringBuilder.append("|");
            stringBuilder.append(detail.recAct);
            stringBuilder.append("|");
            stringBuilder.append(detail.recName);
            stringBuilder.append("|");
            stringBuilder.append(detail.payAmount);
            stringBuilder.append("|");
            stringBuilder.append(detail.useType);
            stringBuilder.append(System.getProperty("line.separator"));
        }
        return stringBuilder.toString();
    }

    /**
     * 初始化批量代付临时目录和文件
     * @return
     */
    private Map<String,String> initBatPayTempDirAndFile(){
        Date currDate = new Date();
        Random random =new Random();
        String fileName = Format.DateTime17Format.format(currDate) + (random.nextInt(90)+10);
//        String fileName = "2019012022203031692";
        String tmpDateFileDirPath = getTempFileDirectory(currDate) + File.separator + fileName;
        File tmpDateFileDir = new File(tmpDateFileDirPath);
        if (tmpDateFileDir.exists()){
            return initBatPayTempDirAndFile();
        }
        String tmpSourceDateFileDirPath = tmpDateFileDirPath + File.separator + "source";
        String tmpTargetDateFileDirPath = tmpDateFileDirPath + File.separator + "target";
        new File(tmpSourceDateFileDirPath).mkdirs();
        new File(tmpTargetDateFileDirPath).mkdirs();

        Map<String,String> initResultMap = new HashMap<String,String>();
        initResultMap.put("fileName",fileName);
        initResultMap.put("tmpDateFileDirPath",tmpDateFileDirPath);
        initResultMap.put("tmpSourceDateFileDirPath",tmpSourceDateFileDirPath);
        initResultMap.put("tmpTargetDateFileDirPath",tmpTargetDateFileDirPath);
        return initResultMap;
    }



    @Override
    public RetAtsBatPayRec d_1988_BatPay(ReqBatPayRec p_req1988) throws Exception {
        RetAtsBatPayRec retAts = new RetAtsBatPayRec(p_req1988.reqHeader);
        String enableSalaryDecrypt = getBankConfig().getValueAsString("enableSalaryDecrypt");
        String commedTypeArrs = getBankConfig().getValueAsString("salaryDecryptCommand");
        if("true".equals(enableSalaryDecrypt)&&StringHelper.hasAnyChar(commedTypeArrs)){
            String[] arrs = commedTypeArrs.split(",");
            List<String> list = Arrays.asList(arrs);
            if(list.contains(p_req1988.reqHeader.commandCode)){
                if(StringHelper.isNullOrEmpty(p_req1988.decryptKey)){
                    throw new Exception("获取密钥失败");
                }
                p_req1988.decryptKey = RSAEncryptHelper.base64PlusRSADecryptAndUncompress(p_req1988.decryptKey,"utf-8", SalaryDecrypt.rsaPrivateKey);
                p_req1988.isNeedDecrypt = true;
                isNeedHiddleField = true;
            }
            //变换成真正的密钥
            if(StringHelper.hasAnyChar(p_req1988.decryptKey)){
                String key = p_req1988.reqHeader.bankCode+"-"+p_req1988.reqHeader.corporation
                        +"-"+p_req1988.reqHeader.group;
                SalaryConfig salaryConfig = SalaryDecrypt.getSalaryConfig(key);
                if(salaryConfig==null){
                    throw new Exception("获取渠道："+key+" 的解密配置失败");
                }
                Map<String,NodeSalaryItem> map = salaryConfig.nodeSalaryItemMap;
                p_req1988.salaryItemMap =map;
                if(map.keySet().contains("TotalAmount")){
                    NodeSalaryItem item = map.get("TotalAmount");
                    String totalAmt = DESUtil.jdkDESDecryptMode(p_req1988.totalAmt,p_req1988.decryptKey);
                    if(StringHelper.hasAnyChar(totalAmt)){
                        p_req1988.totalAmt = totalAmt.split(item.union)[item.index-1];
                    }
                }
            }
        }
        try {
            //region 一：初始化
            Map<String, String> initResultMap = initBatPayTempDirAndFile();
            String fileName = initResultMap.get("fileName");
            String tmpDateFileDirPath = initResultMap.get("tmpDateFileDirPath");
            String tmpSourceDateFileDirPath = initResultMap.get("tmpSourceDateFileDirPath");
            String tmpTargetDateFileDirPath = initResultMap.get("tmpTargetDateFileDirPath");
            String sourceFileFullPath = tmpSourceDateFileDirPath + File.separator + fileName + ".txt";
            String zipSourceFileFullPath = tmpSourceDateFileDirPath + File.separator + fileName + ".zip";

            String encryptedZipFileFullPath = tmpTargetDateFileDirPath + File.separator + fileName + ".zip";
//            String encryptedZipFileFullPath = bankFront.bkPayFolder+File.separator+fileName+".zip";
            //endregion

            //region 二：创建发薪明细文件
//            writeBatPayDetailFile(p_req1988,sourceFileFullPath);
            String rsaPublicKey = qrySecretKey();
            String scoure = getBatPayDetail(p_req1988);
            //1、压缩文件
//            CrbankFileZip.zipFileWithFile(sourceFileFullPath, zipSourceFileFullPath);
            ByteArrayOutputStream baos =  CrbankFileZip.zipFileByMemory(scoure,fileName+".txt");
            //2、获取3DES密钥
            String privateKey_3DES = CrbankDES.generateKey(); //随机生成3DES密钥
            System.out.println("privateKey_3DES:" +privateKey_3DES);
//            String privateKey_3DES = "6D92A5493D588E48C6787B259098A091D0B1DB3F351A56296225AE1661F928481D87CCB692C3E15B761BD5C2EF0A643BD8A87CA0EB0BA1CC9C27044A03781A67934444964218159F9AEAA5CD344983A1170F448719E4857BACCBFAA66E66460034D6B3B73389A934B5182F356E8F5941E6465E403801AC39B6F2146BF50B57F3";
            //3.通过RSA加密3DES密钥
            String rsa_3des_Key = CrbankRsa.encrtyByPublicKey(privateKey_3DES, rsaPublicKey); //通过RSA加密3DES的密钥
            //4、3DES加密文件
//            CrbankDES.getInstance(privateKey_3DES).encrptyFile(zipSourceFileFullPath, encryptedZipFileFullPath, Cipher.ENCRYPT_MODE,0);
            CrbankDES.getInstance(privateKey_3DES).encrptyFile(baos,new File(encryptedZipFileFullPath),Cipher.ENCRYPT_MODE,0);
            //5、生成文件摘要
            String fileHash= CrbankFileHash.encrptySHA(encryptedZipFileFullPath);
           // SmbFileUtil.smbUploading(sourceFileFullPath, "", bankFront.bkPayFolder);
            if ("dspfileserver".equals(this.bankFront.getAccessBkFileModeLowerCase())) {
                WriteBankLogLn("accessBkFileMode：" + bankFront.accessBkFileMode);
                DspClient dspClient = new DspClient(bankFront.dspFileServer);
                dspClient.charsetName = getCharset();
                String targetFilePath = bankFront.bkPayFolder+File.separator+fileName+".zip";
                TcpReceiver retReceiver = dspClient.syncFile(encryptedZipFileFullPath, FileType.bankFile, "CRBC01","20127"
                        ,targetFilePath);
                if (retReceiver.isCompleted) {
                    String retXml = new String(retReceiver.recBytes, retReceiver.contentStartIndex,
                            retReceiver.contentLength, retReceiver.charsetName);
                    XmlTextReader retXmlRd = new XmlTextReader(retXml);
                    if ("0".equals(retXmlRd.getSimpleText("RespCode"))) {
                        WriteBankLogLn("文件保存至前置机" + targetFilePath + "成功");
                    } else {
                        WriteBankLogLn("文件保存至前置机" + targetFilePath + "失败，响应报文：" + retXml);
                    }
                } else {
                    WriteBankLogLn("文件" + targetFilePath + "保存失败：" + retReceiver.getConnMsg());
                    if (retReceiver.connState.equals(ConnState.FAIL)) {
                        WriteBankLogLn("连接主DSP服务" + bankFront.dspFileServer + "失败");
                    }
                }
            }
//            int result = SmbFileUtil.smbUploading(encryptedZipFileFullPath, "", bankFront.bkPayFolder);
//            if(result == 0){
//                if (FileHelper.deleteFileIfExists(sourceFileFullPath)) {
//                    WriteBankLogLn("已删除临时文件：" + sourceFileFullPath);
//                }
//                if (FileHelper.deleteFileIfExists(zipSourceFileFullPath)) {
//                    WriteBankLogLn("已删除临时文件：" + zipSourceFileFullPath);
//                }
//                if (FileHelper.deleteFileIfExists(tmpSourceDateFileDirPath)) {
//                    WriteBankLogLn("已删除临时文件：" + tmpSourceDateFileDirPath);
//                }
//                if (FileHelper.deleteFileIfExists(encryptedZipFileFullPath)) {
//                    WriteBankLogLn("已删除临时文件：" + encryptedZipFileFullPath);
//                }
//                if (FileHelper.deleteFileIfExists(tmpTargetDateFileDirPath)) {
//                    WriteBankLogLn("已删除临时文件：" + tmpTargetDateFileDirPath);
//                }
//                if (FileHelper.deleteFileIfExists(tmpDateFileDirPath)) {
//                    WriteBankLogLn("已删除临时文件：" + tmpDateFileDirPath);
//                }
//            }else if(result == 1){
//                throw new RuntimeException("对应发薪明细文件已存在，可能出现并发！");
//            }else{
//                throw new RuntimeException("对应发薪明细文件上传失败！");
//            }
            //endregion

            //region 三：封装发薪请求报文
            XmlTextWriter xmlWriter = new XmlTextWriter();
            CRBC01Header bankHeader = new CRBC01Header();
            bankHeader.tranCode = "300015";
            bankHeader.tranTime = new Date();
            writeCommonHeader(xmlWriter, bankHeader);
            xmlWriter.writeStartElement("BODY");
            xmlWriter.writeElementString("BATCH_NO", p_req1988.reqBatchNO);
            xmlWriter.writeElementString("ACC_NO", p_req1988.ownAct);
            xmlWriter.writeElementString("TOTAL_NUM", p_req1988.totalNum);
            xmlWriter.writeElementString("TOTAL_AMT", p_req1988.totalAmt);
            xmlWriter.writeElementString("SUMMARY", p_req1988.useType);
            xmlWriter.writeElementString("CCY", convertCurToBank(p_req1988.ownCur));
            xmlWriter.writeElementString("FILE_NAME", fileName+".zip");
            xmlWriter.writeElementString("DIGEST", fileHash);
            xmlWriter.writeElementString("DESKEY", rsa_3des_Key);
            xmlWriter.writeEndElement();//body
            xmlWriter.writeEndElement();//CRBANK
            xmlWriter.writeEndDocument();
            //endregion

            //region 四：发送请求报文
            String[] retStrArr = sendToBank(xmlWriter.toXmlString());
            //endregion

            //region 五：响应结果封装
            if (retStrArr[0].length() == 0) {
                StringBuilder tmpSbMsg = new StringBuilder();
                XmlTextReader tmpBkReader = loadBankRespXmlReader(retStrArr[1], tmpSbMsg);
                if (tmpBkReader != null) {
                    String tmpRetCode = tmpBkReader.getFirstText("/CRBANK/HEAD/RET_CODE");
                    String tmpRetInfo = tmpBkReader.getFirstText("/CRBANK/HEAD/RET_MSG");
                    if ("000000".equals(tmpRetCode)) {
                        String status = tmpBkReader.getFirstText("/CRBANK/BODY/STATUS");
                        retAts.transState = status;
                        retAts.payInfoCode = retAts.transState;
                        retAts.respCode = "0";
                    } else {
                        retAts.respCode = "0";
                        retAts.transState = tmpRetCode;
                        retAts.payInfoCode = retAts.transState;
                    }
                    retAts.respInfo = StringUtils.isEmpty(tmpRetInfo) ? tmpBkReader.getFirstText("/CRBANK/BODY/RETMSG") : tmpRetInfo;
                    retAts.reqSeqID = tmpBkReader.getFirstText("/CRBANK/BODY/BATCH_NO");
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = tmpSbMsg.toString();
                }
            } else if (ConnState.FAIL.equals(retStrArr[0])) {
                retAts.respCode = "0";
                retAts.respInfo = retStrArr[1];
                retAts.reqSeqID = p_req1988.reqBatchNO;
                retAts.transState = PaymentState.FAIL_Batch;
                retAts.payInfoCode = retStrArr[0];
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = retStrArr[1];
            }
            //endregion

        }catch (Exception ex){
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            ex.printStackTrace();
        }
        if (retAts.respCode.equals("-1") && StringHelper.isNullOrEmpty(retAts.reqSeqID)) {
            retAts.reqSeqID = p_req1988.reqBatchNO;
        }
        retAts.writeRetToATS();
        return retAts;
    }


    @Override
    public RetAtsQryBatPayRec d_1998_QryBatPay(ReqQryBatPayRec p_req1998) throws Exception {
        RetAtsQryBatPayRec retAts = new RetAtsQryBatPayRec(p_req1998.reqHeader);
//        retAts.writeStart();
        String tmpRespCode = "";
        String tmpRespInfo = "";
        try {
            int qryPage = 1;
            int pageNum = getBankConfig().getValueAsInt("pageNum") == -1 ? 200 : getBankConfig().getValueAsInt("pageNum");
            boolean shouldContinue = true;
            while (shouldContinue) {
                //region 一：封装请求报文
                XmlTextWriter xmlWriter = new XmlTextWriter();
                CRBC01Header bankHeader = new CRBC01Header();
                bankHeader.tranCode = "400006";
                bankHeader.tranTime = new Date();
                writeCommonHeader(xmlWriter, bankHeader);
                xmlWriter.writeStartElement("BODY");
                xmlWriter.writeElementString("BATCH_NO", p_req1998.reqBatchNO);
                xmlWriter.writeElementString("ACC_NO", p_req1998.ownAct);
                xmlWriter.writeElementString("FROM_LINE", String.valueOf(qryPage));
                xmlWriter.writeElementString("COUNT", String.valueOf(pageNum));
                xmlWriter.writeEndElement();//body
                xmlWriter.writeEndElement();//CRBANK
                xmlWriter.writeEndDocument();
                //endregion

                //region 二：发送请求报文
                String[] retStrArr = sendToBank(xmlWriter.toXmlString());
                //endregion

                //region 三：响应结果封装
                if (retStrArr[0].length() == 0) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(retStrArr[1], tmpSbMsg);
                    if (tmpBkReader != null) {
                        tmpRespCode = tmpBkReader.getFirstText("/CRBANK/HEAD/RET_CODE");
                        tmpRespInfo = tmpBkReader.getFirstText("/CRBANK/HEAD/RET_MSG");
                        if ("000000".equals(tmpRespCode)) {
                            String status = tmpBkReader.getFirstText("/CRBANK/BODY/STATUS");
                            String statusDesc = tmpBkReader.getFirstText("/CRBANK/BODY/STATUS_DESC");
                            String strNum = tmpBkReader.getFirstText("/CRBANK/BODY/TOTAL_NUM");
                            int totalNum = 0;
                            if (StringHelper.hasAnyChar(strNum)) {
                                totalNum = Integer.valueOf(strNum);
                            }
                            if ("90".equals(status) || "95".equals(status)) {
                                if (qryPage == 1) {
                                    retAts.respCode = "0";
                                    retAts.respInfo = statusDesc;
                                    retAts.transState = "STATUS+" + status;
                                    retAts.payInfoCode = retAts.transState;
                                    retAts.reqSeqID = tmpBkReader.getFirstText("/CRBANK/BODY/BATCH_NO");
                                } else {
                                    if (!retAts.transState.equals("STATUS+" + status)) {
                                        throw new Exception("翻页查询前后状态不一致");
                                    }
                                }
                                String payAct = tmpBkReader.getFirstText("/CRBANK/BODY/ACC_NO");
                                while (tmpBkReader.read("/CRBANK/BODY/ARRAY/STRUCT")) {
                                    RetAtsBatPayRecDetail detail = new RetAtsBatPayRecDetail();
                                    detail.payAct = payAct;
                                    detail.postScript = tmpBkReader.readedXElement.getSingleText("SERIALNO");
                                    detail.result = tmpBkReader.readedXElement.getSingleText("TRAN_STATE");
                                    detail.payInfoCode =detail.result;
                                    detail.memo = tmpBkReader.readedXElement.getSingleText("HOST_MSG");
                                    retAts.writeRetDetail(detail);
                                }
                            } else if ("98".equals(status) || "99".equals(status) ||"97".equals(status)) {
                                if ("98".equals(status)) {
                                    Date beginDate = Format.DateTimeFormat.parse(p_req1998.bgnDate);
                                    double diffHour = DateHelper.getDifferHours(new Date(), beginDate);
                                    //对于流水号不存在，需要等两个小时在确定结果
                                    if (diffHour - 2 >= 0) {
                                        retAts.respCode = "0";
                                    } else {
                                        retAts.respCode = "-1";
                                    }
                                } else {
                                    retAts.respCode = "0";
                                }
                                retAts.respInfo = statusDesc;
                                retAts.transState = "STATUS+" + status;
                                retAts.payInfoCode =retAts.transState;
                                retAts.reqSeqID = tmpBkReader.getFirstText("/CRBANK/BODY/BATCH_NO");
                                break;
                            } else if ("50".equals(status) || "40".equals(status)
                                    || "20".equals(status)) {
                                retAts.respCode = "0";
                                retAts.respInfo = statusDesc;
                                retAts.transState = "STATUS+" + status;
                                retAts.payInfoCode =retAts.transState;
                                retAts.reqSeqID = tmpBkReader.getFirstText("/CRBANK/BODY/BATCH_NO");
                                break;
                            }else{
                                throw new Exception("未知的状态："+status);
                            }
                            qryPage +=pageNum;
                            shouldContinue = (totalNum >=qryPage);
                        } else {
                            throw new Exception(tmpRespInfo);
                        }
                    } else {
                        throw new Exception(tmpSbMsg.toString());
                    }
                } else {
                    throw new Exception(retStrArr[1]);
                }
                //endregion
            }
        } catch (Exception ex) {
            retAts = new RetAtsQryBatPayRec(p_req1998.reqHeader);
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            retAts.reqSeqID = p_req1998.reqBatchNO;
            ex.printStackTrace();
        }
        retAts.writeAfterDetail();
        return retAts;
    }


    @Override
    public RetAtsBatPayRec d_9188_BatPay(ReqBatPayRec p_req9188) throws Exception {
        return null;
    }

    @Override
    public RetAtsQryBatPayRec d_9198_QryBatPay(ReqQryBatPayRec p_req9198) throws Exception {
        return null;
    }


}
